package com.zhanghe.mall.service.impl;

import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.zhanghe.mall.pojo.Permissions;
import com.zhanghe.mall.pojo.QRole;
import com.zhanghe.mall.pojo.QRolePermissions;
import com.zhanghe.mall.pojo.Role;
import com.zhanghe.mall.pojo.RolePermissions;
import com.zhanghe.mall.pojo.System;
import com.zhanghe.mall.pojo.repository.PermissionsRepository;
import com.zhanghe.mall.pojo.repository.RolePermissionsRepository;
import com.zhanghe.mall.pojo.repository.RoleRepository;
import com.zhanghe.mall.service.RoleService;
import com.zhanghe.mall.service.dto.AddRoleDTO;
import com.zhanghe.mall.service.dto.EditRoleDTO;
import com.zhanghe.mall.service.dto.FindRoleDTO;
import com.zhanghe.mall.service.dto.out.PermissionsDTO;
import com.zhanghe.mall.service.dto.out.RoleDTO;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class RoleServiceImpl implements RoleService {

  @Autowired
  private RoleRepository roleRepository;

  @Autowired
  private PermissionsRepository permissionsRepository;

  @Autowired
  private RolePermissionsRepository rolePermissionsRepository;

  @Autowired
  private JPAQueryFactory queryFactory;

  @Override
  public Page<RoleDTO> findByPage(FindRoleDTO findRoleDTO) {
    JPAQuery query = queryFactory.select(Projections.bean(
        RoleDTO.class,QRole.role.id,QRole.role.name,QRole.role.description
    )).from(QRole.role).offset(findRoleDTO.getPage()).limit(findRoleDTO.getSize());
    List<RoleDTO> list = query.fetch();
    Long total = query.fetchCount();
    return new PageImpl<>(list,PageRequest.of(findRoleDTO.getPage(),findRoleDTO.getSize()),total);
  }

  @Override
  public List<PermissionsDTO> findRolePermissions(Long roleId) {
    JPAQuery query = queryFactory.select(Projections.bean(
        PermissionsDTO.class,
        QRolePermissions.rolePermissions.permissions.id,QRolePermissions.rolePermissions.permissions.parentId,
        QRolePermissions.rolePermissions.permissions.name,QRolePermissions.rolePermissions.permissions.routeUrl,
        QRolePermissions.rolePermissions.permissions.sort,QRolePermissions.rolePermissions.permissions.type,
        QRolePermissions.rolePermissions.permissions.url
    )).from(QRolePermissions.rolePermissions).where(
        QRolePermissions.rolePermissions.role.id.eq(roleId),
        QRolePermissions.rolePermissions.role.isDelete.eq(false),
        QRolePermissions.rolePermissions.permissions.isDelete.eq(false)
    );
    List<PermissionsDTO> list = query.fetch();

    return getSubList(null,list);
  }

  @Override
  public Role insert(AddRoleDTO addRoleDTO) {
    Role role = new Role();
    role.setName(addRoleDTO.getName());
    role.setDescription(addRoleDTO.getDescription());
    System system = new System();
    system.setId(addRoleDTO.getSystemId());
    role.setSystem(system);
    role = roleRepository.save(role);

    insertRolePermissions(role,addRoleDTO.getPermissions());
    return role;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public Role edit(EditRoleDTO editRoleDTO) {
    //先删除原先的权限
    queryFactory.delete(QRolePermissions.rolePermissions).where(
        QRolePermissions.rolePermissions.role.id.eq(editRoleDTO.getId())
    ).execute();

    queryFactory.update(QRole.role).set(
        QRole.role.editTime,new Date()
    ).set(
        QRole.role.description,editRoleDTO.getDescription()
    ).set(
        QRole.role.name,editRoleDTO.getName()
    ).set(
        QRole.role.system.id,editRoleDTO.getSystemId()
    ).execute();

    Role role = roleRepository.getOne(editRoleDTO.getId());
    insertRolePermissions(role,editRoleDTO.getPermissions());
    return role;
  }

  private List<PermissionsDTO> getSubList(PermissionsDTO parent,List<PermissionsDTO> list){
    ArrayList<PermissionsDTO> result = new ArrayList<>();
    Iterator<PermissionsDTO> it = list.iterator();
    while (it.hasNext()){
      PermissionsDTO dto = it.next();
      if(parent==null){
        if(dto.getParentId() == null){
          it.remove();
          result.add(dto);
        }
      }else{
        if(dto.getParentId() != null && dto.getParentId().equals(parent.getId())){
          it.remove();
          result.add(dto);
        }
      }
    }
    for(PermissionsDTO permissionsDTO:result){
      permissionsDTO.setChild(getSubList(permissionsDTO,list));
    }
    return result;
  }

  private void insertRolePermissions(Role role,List<Long> permissionsList){
    for(Long permissionId:permissionsList){
      Permissions permissions = permissionsRepository.getOne(permissionId);
      RolePermissions rolePermissions = new RolePermissions();
      rolePermissions.setRole(role);
      rolePermissions.setPermissions(permissions);
      rolePermissionsRepository.save(rolePermissions);
    }
  }
}
